from django.db import models
from django.contrib.auth.models import User

from django.utils import timezone

from django.urls import reverse 

# version_7
import markdown
from django.utils.html import strip_tags

# Create your models here.


class Category(models.Model):
    """
    django 要求模型必须继承 models.Model 类。
    Category 只需要一个简单的分类名 name 就可以了。
    CharField 指定了分类名 name 的数据类型，CharField 是字符型，
    CharField 的 max_length 参数指定其最大长度，超过这个长度的分类名就不能被存入数据库。
    当然 django 还为我们提供了多种其它的数据类型，如日期时间类型 DateTimeField、整数类型 IntegerField 等等。
    django 内置的全部类型可查看文档：
    https://docs.djangoproject.com/en/2.2/ref/models/fields/#field-types
    """
    
    # 汉化添加了verbose_name='分类名'参数，verbose_name默认可以不写，位于field的第一个参数 
    name = models.CharField('分类名',max_length=100)

    # 汉化，新加了子类
    class Meta:
        verbose_name = '分类'
        verbose_name_plural = verbose_name

    # 设置返回对象描述的方法__str__()
    def __str__(self):
        return self.name

class Tag(models.Model):
    """
    标签Tag也比较简单，和Category一样。
    再次强调一定要继承models.Model类
    """

    # 汉化
    name = models.CharField('标签名',max_length=100)

    # 汉化，新加了子类
    class Meta:
        verbose_name = '标签'
        verbose_name_plural = verbose_name


    # 设置返回对象描述的方法__str__()
    def __str__(self):
        return self.name

class Post(models.Model):
    """
    文章的数据库表，稍微复杂一点，主要是涉及到的字段多
    """

    # 文章标题
    title = models.CharField('标题',max_length=70)

    # 文章正文，使用textfield
    body = models.TextField('正文')

    # 创建时间和更新时间
    created_time = models.DateTimeField('创建时间',default=timezone.now)
    modified_time = models.DateTimeField('更新时间')


    # 文章摘要，默认情况下CharField要求必须存入数据(不可为空)
    # 指定CharField的blank=True后即可为空
    excerpt = models.CharField('摘要',max_length=200,blank=True)


    # 这是分类与标签，分类与标签的模型我们已经定义在上面。
    # 我们在这里把文章对应的数据库表和分类、标签对应的数据库表关联了起来，但是关联形式稍微有点不同。
    # 我们规定一篇文章只能对应一个分类，但是一个分类下可以有多篇文章，所以我们使用的是 ForeignKey，即一
    # 对多的关联关系。且自 django 2.0 以后，ForeignKey 必须传入一个 on_delete 参数用来指定当关联的
    # 数据被删除时，被关联的数据的行为，我们这里假定当某个分类被删除时，该分类下全部文章也同时被删除，因此
    # 使用 models.CASCADE 参数，意为级联删除。
    # 而对于标签来说，一篇文章可以有多个标签，同一个标签下也可能有多篇文章，所以我们使用ManyToManyField，表明这是多对多的关联关系。
    # 同时我们规定文章可以没有标签，因此为标签 tags 指定了 blank=True。
    
    category = models.ForeignKey(Category,verbose_name='分类',on_delete=models.CASCADE)   #foreignkey默认第一个参数是与其关联的model，所以只能显示的用verbose_name
    tags = models.ManyToManyField(Tag,blank=True,verbose_name='标签')

    # 文章作者，这里User是从django.contrib.auth.models导入的
    # django.contrib.auth是django内置的应用，专门用于处理网站用户的注册，登陆的流程，User是django已经写好的
    # 这里通过ForeignKey把文章和User关联起来
    # 作者和文章是一对多的关系

    author = models.ForeignKey(User,on_delete=models.CASCADE,verbose_name='作者')


    # version_12 添加阅读量计算功能
    views = models.PositiveIntegerField(default=0)

    # 汉化，新加了子类
    class Meta:
        verbose_name = '文章'
        verbose_name_plural = verbose_name
        # version_11 指定排序属性
        ordering = ['-created_time']

    # 设置返回对象描述的方法__str__()
    def __str__(self):
        return self.title


    def save(self,*args,**kwargs):
        self.modified_time = timezone.now()
    
        # version_7 自动生成文章摘要，重新覆写save函数
        # 实例化一个Markdown类，用于渲染body的文本
        md = markdown.Markdown(extensions = [
            'markdown.extensions.extra',
            'markdown.extensions.codehilite',
            # 不需要生成文章目录，所以去掉toc
        ])

        # 从文本中截取前5个字符
        self.excerpt = strip_tags(md.convert(self.body))[:5]
        super().save(*args,**kwargs)

    # 自定义get_absolute=_url方法
    # 记得从django.urls 中导入reverse函数
    
    # version_12 新增累积功能
    def increase_views(self):
       self.views += 1
       self.save(update_fields=['views'])

    def get_absolute_url(self):
        return reverse('polls:detail',kwargs={'pk':self.pk})
